import * as XLSX from 'xlsx-js-style';
import moment from 'moment';

// 定义表格列配置接口
interface TableColumn {
  label: string; // 列标题
  prop: string; // 数据属性名
  align?: string; // 对齐方式
  hidden?: boolean; // 是否隐藏
  children?: TableColumn[]; // 子列
}

// 定义导出配置接口
interface ExportConfig {
  thead: TableColumn[]; // 表头配置
  tbody: any[]; // 表格数据
  fileName: string; // 文件名称
  isSummary?: boolean; // 是否显示统计信息
  mergeCode?: string; // 合并code
  mergeCodeArr?: any; // 合并的组
}

/**
 * 导出Excel文件
 * @param config 导出配置对象
 * @param data 可选的数据上下文对象
 */
export const exportData = (config: ExportConfig, data?: any) => {
  const { thead, tbody, isSummary, fileName, mergeCode, mergeCodeArr } = config;
  // 过滤掉隐藏的列
  const visibleThead = thead.filter((el) => !el.hidden);

  // 获取表头的最大深度（用于处理多级表头）
  const maxDepth: number = getMaxDepth(visibleThead);

  // 初始化表头数组，每个层级一个数组
  let wsThead: any[][] = [];
  for (let index = 0; index < maxDepth; index++) {
    wsThead[index] = [];
  }

  // 用于存储扁平化的表头配置
  let flatThead: any[] = [];

  // 存储合并单元格的范围
  const merges: any[] = [];

  // 构建表头结构
  buildHeaderStructure(visibleThead, 1, maxDepth);
  const _rowCode = mergeCode ? tbody[0][mergeCode] : '';
  let mergeValue = _rowCode;
  let mergeStartIndex = maxDepth; // 起始合并行（考虑表头高度）
  let mergeSpan = 0;
  let isSingleRow = false;

  const wsTbody: any[] = [];

  tbody.forEach((el: any, index: number) => {
    if (mergeCode && mergeCodeArr?.length > 0) {
      const currentValue = el[mergeCode];
      if (currentValue === mergeValue) {
        mergeSpan++;
      } else {
        // 当前值不一致，生成上一组的合并信息
        if (mergeSpan > 0) {
          const startRow = mergeStartIndex;
          const endRow = mergeStartIndex + mergeSpan - 1;
          mergeCodeArr.forEach((code: string) => {
            const theadIndex = flatThead.findIndex((thead: any) => code === thead.prop);
            if (theadIndex !== -1) {
              merges.push({
                s: { c: theadIndex, r: startRow },
                e: { c: theadIndex, r: endRow },
              });
            }
          });
        }

        // 重置当前值和起始索引
        mergeValue = currentValue;
        mergeStartIndex = mergeStartIndex + mergeSpan;
        mergeSpan = 1;
        isSingleRow = !isSingleRow;
      }
    }
    el.isSingleRow = isSingleRow;
    // 构建当前行数据
    wsTbody.push(flatThead.map((item: any) => (el[item.prop] || el[item.prop] === 0 ? el[item.prop] : '')));
  });

  // 处理最后一组数据
  if (mergeCode && mergeCodeArr?.length > 0 && mergeSpan > 0) {
    const startRow = mergeStartIndex;
    const endRow = mergeStartIndex + mergeSpan - 1;
    mergeCodeArr.forEach((code: string) => {
      const theadIndex = flatThead.findIndex((thead: any) => code === thead.prop);
      if (theadIndex !== -1) {
        merges.push({
          s: { c: theadIndex, r: startRow },
          e: { c: theadIndex, r: endRow },
        });
      }
    });
  }
  // return;
  // 合并表头和内容
  const wsData: any[] = [...wsThead, ...wsTbody];

  // 如果需要显示统计信息
  if (isSummary) {
    const wsSummary: any[] = flatThead.map((item: any, index: number) => {
      return index === 0 ? `共计 ${wsTbody.length} 条数据` : '';
    });
    wsData.push(wsSummary);

    // 合并摘要行
    merges.push({
      s: { c: 0, r: wsData.length - 1 },
      e: { c: flatThead.length - 1, r: wsData.length - 1 },
    });
  }

  // 创建工作表
  const worksheet = XLSX.utils.aoa_to_sheet(wsData);

  // 创建工作簿
  const workbook = XLSX.utils.book_new();

  // 添加自动筛选功能
  worksheet['!autofilter'] = {
    ref: `A${maxDepth}:${getExcelColumnName(flatThead.length)}${maxDepth}`,
  };

  // 定义样式
  const headerStyle = createHeaderStyle(); // 表头样式
  const allCellsStyle = { border: createBorderStyle() }; // 所有单元格边框样式

  // 配置列宽计算参数
  const configWidth = {
    defaultMinWidth: 10,
    defaultMaxWidth: 120,
    widthExpansionFactor: 1,
    padding: 4,
  };

  // 计算每列最大宽度
  const maxColumnWidths: number[] = Array.from({ length: wsData[0]?.length || 0 }, () => 0);

  // 遍历数据计算实际列宽
  wsData.forEach((row) => {
    row.forEach((cell: any, index: number) => {
      const cellStr = (cell?.toString() ?? '').trim();
      let cellLength = 0;

      // 计算字符宽度：中文占2个单位，其他占1个单位
      for (let char of cellStr) {
        cellLength += /[\u4e00-\u9fa5]/.test(char) ? 2 : 1;
      }

      // 更新最大列宽
      if (cellLength > maxColumnWidths[index]) {
        maxColumnWidths[index] = cellLength;
      }
    });
  });

  // 应用计算结果到工作表的列宽配置
  worksheet['!cols'] = maxColumnWidths.map((width) => ({
    wch: Math.min(Math.max(Math.ceil(width * configWidth.widthExpansionFactor) + configWidth.padding, configWidth.defaultMinWidth), configWidth.defaultMaxWidth),
  }));

  // 应用合并单元格设置
  worksheet['!merges'] = merges;

  // 给所有数据单元格添加样式
  applyCellStyle(worksheet, wsData, allCellsStyle, flatThead);

  // 应用表头样式
  applyHeaderStyle(worksheet, wsThead, headerStyle, flatThead, isSummary, wsData, tbody);

  // 把工作表加入到工作簿中
  XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1');

  // 生成Excel文件并触发下载
  const wopts: any = { bookType: 'xlsx', type: 'array' };
  const wbout = XLSX.write(workbook, wopts);
  const blob = new Blob([wbout], { type: 'application/octet-stream' });
  const link = document.createElement('a');
  link.href = URL.createObjectURL(blob);
  const time = moment(new Date()).format('YYYYMMDDHHmmss');
  link.download = `${fileName}${time}.xlsx`;
  link.click();
  URL.revokeObjectURL(link.href);
  if (data) data.loading = false;

  /**
   * 将列索引转换为Excel列字母标识
   * @param columnIndex 列索引
   * @returns Excel列字母标识（如A、B、AA等）
   */
  function getExcelColumnName(columnIndex: number): string {
    let columnName = '';
    let dividend = columnIndex;
    let modulo;

    while (dividend > 0) {
      modulo = (dividend - 1) % 26;
      columnName = String.fromCharCode(65 + modulo) + columnName;
      dividend = Math.floor((dividend - modulo) / 26);
    }

    return columnName;
  }

  /**
   * 创建边框样式
   * @param color 边框颜色（十六进制）
   * @returns 边框样式对象
   */
  function createBorderStyle(color = '000000') {
    return {
      top: { style: 'thin', color: { auto: 1 } },
      left: { style: 'thin', color: { auto: 1 } },
      bottom: { style: 'thin', color: { auto: 1 } },
      right: { style: 'thin', color: { auto: 1 } },
    };
  }

  /**
   * 创建表头样式
   * @returns 表头样式对象
   */
  function createHeaderStyle() {
    return {
      fill: { fgColor: { rgb: 'e0e6ff' } }, // 浅蓝色背景
      font: { bold: true }, // 加粗字体
      border: createBorderStyle(), // 添加边框样式
      alignment: {
        // 文字居中对齐
        horizontal: 'center',
        vertical: 'center',
      },
    };
  }

  /**
   * 递归构建表头结构
   * @param arr 当前处理的表头数组
   * @param depth 当前层级深度
   * @param maxDepth 最大层级深度
   * @param startCol 起始列号
   */
  function buildHeaderStructure(arr: any[], depth: number = 1, maxDepth: number, startCol: number = 0) {
    if (arr && arr.length) {
      let colCounter = 0;

      arr.forEach((el: any) => {
        // 填充当前层级的表头标签
        wsThead[depth - 1].push(el.label);

        if (el.children && el.children.length > 0) {
          // 如果存在子节点，计算子节点数量
          const nodeCount = countNodes(el.children);

          // 在当前层级填充空白单元格
          for (let i = 1; i < nodeCount; i++) {
            wsThead[depth - 1].push('');
          }

          // 添加父级表头的合并范围
          merges.push({
            s: { c: colCounter, r: depth - 1 },
            e: { c: colCounter + nodeCount - 1, r: depth - 1 },
          });

          // 递归处理下一级表头
          buildHeaderStructure(el.children, depth + 1, maxDepth, colCounter);
          colCounter += nodeCount;
        } else {
          // 如果是叶子节点
          flatThead.push(el);

          // 如果当前深度小于最大深度，在下层添加空白单元格
          if (depth < maxDepth) {
            for (let i = 0; i < maxDepth - depth; i++) {
              wsThead[depth + i].push('');
            }

            // 添加垂直方向的合并范围
            merges.push({
              s: { c: colCounter, r: depth - 1 },
              e: { c: colCounter, r: maxDepth - 1 },
            });
          }
          colCounter++;
        }
      });
    }
  }

  /**
   * 应用单元格样式
   * @param worksheet 工作表对象
   * @param wsData 单元格数据
   * @param style 样式对象
   * @param thead 表头配置
   */
  function applyCellStyle(worksheet: any, wsData: any, style: any, thead: any[]) {
    for (let R = 0; R < wsData.length; ++R) {
      for (let C = 0; C < wsData[R].length; ++C) {
        const cellAddress = XLSX.utils.encode_cell({ c: C, r: R });

        // 确保单元格存在
        if (!worksheet[cellAddress]) {
          worksheet[cellAddress] = { v: '', s: {} };
        }

        // 应用样式
        worksheet[cellAddress].s = {
          ...style,
          alignment: {
            horizontal: thead[C]?.align || 'left',
            vertical: 'center',
          },
        };
      }
    }
  }

  /**
   * 应用表头样式
   * @param worksheet 工作表对象
   * @param wsThead 表头数据
   * @param style 样式对象
   * @param thead 表头配置
   * @param isSummary 是否显示摘要
   * @param wsData 全部数据
   */
  function applyHeaderStyle(worksheet: any, wsThead: any[][], style: any, thead: any[], isSummary: boolean = false, wsData: any[]) {
    // 应用表头行的样式
    for (let row = 0; row < wsThead.length; row++) {
      for (let col = 0; col < thead.length; col++) {
        const cellAddress = XLSX.utils.encode_cell({ c: col, r: row });
        if (worksheet[cellAddress]) {
          worksheet[cellAddress].s = style;
        }
      }
    }
    //
    tbody.forEach((el: any, index: number) => {
      if (el.isSingleRow) {
        for (let col = 0; col < flatThead.length; col++) {
          const cellAddress = XLSX.utils.encode_cell({ c: col, r: index + maxDepth });
          if (worksheet[cellAddress]) {
            worksheet[cellAddress].s = {
              ...worksheet[cellAddress].s,
              fill: { fgColor: { rgb: 'e8e8e8' } }, // 浅蓝色背景
            };
          }
        }
      }
    });
    // 如果显示摘要，应用表头样式到摘要行
    if (isSummary) {
      const summaryRow = wsData.length - 1;
      for (let col = 0; col < thead.length; col++) {
        const cellAddress = XLSX.utils.encode_cell({ c: col, r: summaryRow });
        if (worksheet[cellAddress]) {
          worksheet[cellAddress].s = style;
        }
      }
    }
  }

  /**
   * 计算子节点数量
   * @param arr 需要计算的数组
   * @returns 节点数量
   */
  function countNodes(arr: any[]): number {
    if (!Array.isArray(arr)) return 0;

    let count = 0;

    for (let item of arr) {
      if (Array.isArray(item.children) && item.children.length > 0) {
        count += countNodes(item.children);
      } else {
        count += 1;
      }
    }

    return count;
  }

  /**
   * 计算表头的最大深度
   * @param arr 表头数组
   * @returns 最大深度
   */
  function getMaxDepth(arr: any[]): number {
    if (!Array.isArray(arr)) return 0;
    if (arr.length === 0) return 1;

    let maxChildDepth = 0;

    for (let item of arr) {
      maxChildDepth = Math.max(maxChildDepth, getMaxDepth(item.children));
    }

    return 1 + maxChildDepth;
  }
};
